package com.ruoyi.file.utils;

import com.ruoyi.common.enums.CommonStatus;
import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException;
import com.ruoyi.common.exception.file.FileSizeLimitExceededException;
import com.ruoyi.common.exception.file.InvalidExtensionException;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.MimeTypeUtils;
import com.ruoyi.common.utils.sign.Md5Utils;
import com.ruoyi.file.mapper.FilesMapper;
import com.ruoyi.file.model.vo.Files;
import com.ruoyi.framework.config.CustomMinioClient;
import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.Objects;

import static com.ruoyi.common.utils.file.FileUploadUtils.assertAllowed;
import static com.ruoyi.common.utils.file.FileUploadUtils.extractFilename;

@Slf4j
@Component
public class MinioTool {

    @Value(value = "${minio.endpoint}")
    private String endpoint;
    @Value(value = "${minio.access-key}")
    private String accessKey;
    @Value(value = "${minio.secret-key}")
    private String secretKey;

    @Value(value = "${minio.expiry}")
    private Integer expiry;
    @Value(value = "${minio.default-bucket}")
    private String bucketName;
    @Resource
    private FilesMapper filesMapper;

    private CustomMinioClient customMinioClient;

    /**
     * 用spring的自动注入会注入失败
     */
    @PostConstruct
    public void init() {
        MinioClient minioClient = MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
        customMinioClient = new CustomMinioClient(minioClient);
    }

    public String uploadMinio(String bucketName, MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, FileNameLengthLimitExceededException,
            InvalidExtensionException {
        int fileNameLength = Objects.requireNonNull(file.getOriginalFilename()).length();
        if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
        }

        assertAllowed(file, allowedExtension);

        try {
            String fileName = extractFilename(file);
            //调用自定义MinioUtil类方法
            return uploadFile(bucketName, fileName, file);
        } catch (Exception e) {
            log.error(e.getMessage());

        }
        return "";

    }

    public final String uploadMinio(MultipartFile file) throws IOException {
        try {
            String url = endpoint + uploadMinio(bucketName, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
            Files files = new Files();
            files.setUrl(url);
            String originalFilename = file.getOriginalFilename();
            files.setFileName(originalFilename);
            files.setFileSize(file.getSize());
            files.setBucketName(bucketName);
            assert originalFilename != null;
            int i = originalFilename.lastIndexOf('.');
            if (i > 0) {
                files.setFileType(originalFilename.substring(i + 1));
            }
            files.setFileMd5(Md5Utils.getFileMD5(file));
            files.setFileType(file.getContentType());
            files.setIsDelete(CommonStatus.OK.getCode());
            files.setEnable(CommonStatus.OK.getCode());
            files.setCreateTime(LocalDateTime.now());
            files.setUpdateTime(LocalDateTime.now());
            filesMapper.insertXml(files);
            return url;
        } catch (Exception e) {
            throw new IOException(e.getMessage(), e);
        }
    }

    /**
     * @param bucketName 桶名称
     * @param fileName   文件名
     * @throws IOException 异常
     */
    public String uploadFile(String bucketName, String fileName, MultipartFile multipartFile) throws IOException {
        String url = "";
        try (InputStream inputStream = multipartFile.getInputStream()) {
            boolean found = customMinioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (!found) {
                customMinioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                /*
                  bucket权限-读写
                 */
                String READ_WRITE = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::" + bucketName + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\"],\"Resource\":[\"arn:aws:s3:::" + bucketName + "/*\"]}]}";
                customMinioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(READ_WRITE).build());
            }
            customMinioClient.putObject(PutObjectArgs.builder().bucket(bucketName)
                    .object(fileName)
                    .stream(inputStream, multipartFile.getSize(), -1)
                    .contentType(multipartFile.getContentType()).build()
            );
            //路径获取
            url = "/" + bucketName + "/" + fileName;
            //常规访问路径获取
            return url;
        } catch (Exception e) {
            throw new IOException(e.getMessage(), e);
        }
    }
}
